#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
using std::cerr;
using std::string;
using std::vector;
#include <cstdlib>

#include <stlhelper.h>
#include <portable_timer.h>
#include <set_mark_diff.h>
//inline
//void set_mark_diff(	InIt1 i1, InIt1 last1,
//					InIt2 i2, InIt2 last2,
//					InIt3 unique_to_set1,
//					InIt4 unique_to_set2,
//					PRED_Less pred_less,
//					PRED_Mark1 pred_mark1,
//					PRED_Mark2 pred_mark2);
//

template<typename T>
void print_vector(const std::vector<T>& vec)
{
	for (unsigned i = 0; i < vec.size(); ++i)
	{
		cerr << (unsigned)vec[i] << ", ";
	}
	cerr << "\n";
}

void print_marked_vector(const std::vector<char>& marked, const std::vector<unsigned>& vec)
{
	for (unsigned i = 0; i < marked.size(); ++i)
	{
		if (marked[i])
			cerr << (unsigned)vec[i] << ", ";
	}
}

void add_marked_vector(const std::vector<char>& marked, const std::vector<unsigned>& vec1
								, std::vector<unsigned>& vec2)
{
	for (unsigned i = 0; i < marked.size(); ++i)
	{
		if (marked[i])
			vec2.push_back(vec1[i]);
	}
}


struct mark_char
{
	string name;
	mark_char(const string& name_) : name(name_){}
	void operator()(char& c)
	{
		c = 1;}
};

void create_vector(std::vector<unsigned>& set1, unsigned vec_size, unsigned rand_range)
{
	t_portable_timer timer;
	cerr << "Create vector ";
	for (unsigned i = 0; i < vec_size; i++)
		set1.push_back(rand() % rand_range);
	cerr << timer.pretty_reset() << "\n";

	cerr << "Sort ";
	sort(set1.begin(), set1.end());
	cerr << timer.pretty_reset() << "\n";

	cerr << "Remove duplicates ";
	remove_duplicates(set1);
	cerr << timer.pretty_reset() << "\n";
}


int main (int argc, char *argv[])
{
	const unsigned VEC_SIZE = 200000;
	const unsigned RAND_ITER = 400000;

	{
		vector<unsigned> set1;
		create_vector(set1, VEC_SIZE, RAND_ITER);
		vector<unsigned> set2;
		create_vector(set2, VEC_SIZE, RAND_ITER);
	
		std::vector<char> set1_unique(set1.size(), 0);
		std::vector<char> set2_unique(set2.size(), 0);
	
		t_portable_timer timer;
	
		cerr << set1.size() << " = set1 size\n";
		cerr << set2.size() << " = set2 size\n";
		cerr << "Set_mark_diff ";
		set_mark_diff(	set1.begin(), set1.end(),
						set2.begin(), set2.end(),
						set1_unique.begin(),
						set2_unique.begin(),
						std::less<unsigned>(),
						mark_char("set1"),
						mark_char("set2"));
		cerr << timer.pretty_reset() << "\n";
	
		unsigned cnt_unique1 = std::count(set1_unique.begin(), set1_unique.end(), 1);
		unsigned cnt_unique2 = std::count(set2_unique.begin(), set2_unique.end(), 1);
		cerr << cnt_unique1 << " unique to vec 1:\n";
		cerr << cnt_unique2 << " unique to vec 2:\n";
	
		cerr << "Now make both lists the same, merging them together ";
		add_marked_vector(set1_unique, set1, set2);
		add_marked_vector(set2_unique, set2, set1);
		cerr << timer.pretty_reset() << "\n";
	
		cerr << "Sort both sets ";
		sort(set1.begin(), set1.end());
		sort(set2.begin(), set2.end());
		cerr << timer.pretty_reset() << "\n";
	
		cerr << "Allocate flags ";
		set1_unique.assign(set1.size(), 0);
		set2_unique.assign(set2.size(), 0);
		cerr << timer.pretty_reset() << "\n";
	
		cerr << set1.size() << " = set1 size\n";
		cerr << set2.size() << " = set2 size\n";
		cerr << "Set_mark_diff ";
		set_mark_diff(	set1.begin(), set1.end(),
						set2.begin(), set2.end(),
						set1_unique.begin(),
						set2_unique.begin(),
						std::less<unsigned>(),
						mark_char("set1"),
						mark_char("set2"));
		cerr << timer.pretty_reset() << "\n";
	
		cnt_unique1 = std::count(set1_unique.begin(), set1_unique.end(), 1);
		cnt_unique2 = std::count(set2_unique.begin(), set2_unique.end(), 1);
		cerr << cnt_unique1 << " unique to vec 1:\n";
		cerr << cnt_unique2 << " unique to vec 2:\n";
	}

	{
		vector<unsigned> set1;
		create_vector(set1, VEC_SIZE, RAND_ITER);
		vector<unsigned> set2;
		create_vector(set2, VEC_SIZE, RAND_ITER);

		std::vector<char> set1_unique(set1.size(), 0);
		std::vector<char> set2_unique(set2.size(), 0);

		t_portable_timer timer;

		cerr << set1.size() << " = set1 size\n";
		cerr << set2.size() << " = set2 size\n";
		cerr << "Set_mark_diff ";
		set_mark_diff_cont(	set1,
						set2,
						set1_unique.begin(),
						set2_unique.begin(),
						std::less<unsigned>(),
						mark_char("set1"),
						mark_char("set2"));
		cerr << timer.pretty_reset() << "\n";

		unsigned cnt_unique1 = std::count(set1_unique.begin(), set1_unique.end(), 1);
		unsigned cnt_unique2 = std::count(set2_unique.begin(), set2_unique.end(), 1);
		cerr << cnt_unique1 << " unique to vec 1:\n";
		cerr << cnt_unique2 << " unique to vec 2:\n";

		cerr << "Now make both lists the same, merging them together ";
		add_marked_vector(set1_unique, set1, set2);
		add_marked_vector(set2_unique, set2, set1);
		cerr << timer.pretty_reset() << "\n";

		cerr << "Sort both sets ";
		sort(set1.begin(), set1.end());
		sort(set2.begin(), set2.end());
		cerr << timer.pretty_reset() << "\n";

		cerr << "Allocate flags ";
		set1_unique.assign(set1.size(), 0);
		set2_unique.assign(set2.size(), 0);
		cerr << timer.pretty_reset() << "\n";

		cerr << set1.size() << " = set1 size\n";
		cerr << set2.size() << " = set2 size\n";
		cerr << "Set_mark_diff ";
		set_mark_diff_cont(	set1,
						set2,
						set1_unique.begin(),
						set2_unique.begin(),
						std::less<unsigned>(),
						mark_char("set1"),
						mark_char("set2"));
		cerr << timer.pretty_reset() << "\n";

		cnt_unique1 = std::count(set1_unique.begin(), set1_unique.end(), 1);
		cnt_unique2 = std::count(set2_unique.begin(), set2_unique.end(), 1);
		cerr << cnt_unique1 << " unique to vec 1:\n";
		cerr << cnt_unique2 << " unique to vec 2:\n";
	}

	return(0);
}
